package avicit.bdp.dds.api.job;

import avicit.bdp.common.utils.DateUtils;
import avicit.bdp.common.utils.EntityUtils;
import avicit.bdp.common.utils.redis.RedisLockUtils;
import avicit.bdp.dds.dispatch.enums.ExecutionStatus;
import avicit.bdp.dds.api.dto.StateDto;
import avicit.bdp.dds.api.service.DataStatService;
import avicit.bdp.dds.api.service.ProcessInstanceService;
import avicit.bdp.dds.api.service.ProjectService;
import avicit.bdp.dds.dao.entity.DataStat;
import avicit.bdp.dds.dao.entity.Project;
import avicit.platform6.commons.utils.ComUtil;
import com.google.common.collect.Maps;
import org.apache.commons.collections4.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author xugb
 */
@Component
public class BdpDdsJob {

    private static final Logger logger = LoggerFactory.getLogger(BdpDdsJob.class);

    @Autowired
    private DataStatService stateService;

    @Autowired
    private ProcessInstanceService processInstanceService;

    @Autowired
    private ProjectService projectService;

    @Autowired
    private RedisLockUtils lockUtils;

    private static final int HOURS = 24;

    private static final String LOCK_KEY = "bdp:dds:stat-job";

    @Scheduled(cron = "0 0 3 * * ?")
    public void stateTaskCount() throws Exception {
        boolean lock = lockUtils.lock(LOCK_KEY);
        if (lock) {
            logger.info("开始统计开发工作台运行情况");
            long startTime = System.currentTimeMillis();
            Map<String, Object> successMap = Maps.newHashMap();
            Map<String, Object> failMap = Maps.newHashMap();
            Map<String, DataStat> statMap = new HashMap<>(16);
            String yesterday = DateUtils.getDayNumBeforeToday(1);
            List<DataStat> insertList = new ArrayList<>();
            List<DataStat> updateList = new ArrayList<>();

            try {
                List<StateDto> successDataList = processInstanceService.getDataCount(yesterday, ExecutionStatus.SUCCESS.getCode());
                for (StateDto successDatum : successDataList) {
                    successMap.put(successDatum.getProjectId() + successDatum.getStatDate(), successDatum.getStatCount());
                }
                List<StateDto> failDataList = processInstanceService.getDataCount(yesterday, ExecutionStatus.FAILURE.getCode());
                for (StateDto failDatum : failDataList) {
                    failMap.put(failDatum.getProjectId() + failDatum.getStatDate(), failDatum.getStatCount());
                }

                logger.info("开始统计昨日运行情况，统计日期：" + yesterday);
                List<DataStat> statList = stateService.getDataByProjectId(yesterday, null);
                for (DataStat stat : statList) {
                    statMap.put(stat.getProjectId() + stat.getStatDate(), stat);
                }

                List<Project> projectList = projectService.selectListAll();
                for (Project project : projectList) {
                    for (int i = 0; i < HOURS; i++) {
                        String hour = i + "";
                        if (hour.length() == 1) {
                            hour = "0" + i;
                        }
                        String statDate = yesterday + hour;
                        String key = project.getId() + statDate;
                        Integer successCount = MapUtils.getInteger(successMap, key, 0);
                        Integer failCount = MapUtils.getInteger(failMap, key, 0);
                        DataStat dto = statMap.get(key);
                        if (dto != null) {
                            dto.setSuccessCount(successCount);
                            dto.setFailCount(failCount);
                            updateList.add(dto);
                        } else {
                            dto = new DataStat();
                            dto.setId(ComUtil.getId());
                            dto.setStatDate(statDate);
                            dto.setProjectId(project.getId());
                            dto.setSuccessCount(successCount);
                            dto.setFailCount(failCount);
                            dto.setSuccessHistoryCount(0);
                            dto.setFailHistoryCount(0);
                            EntityUtils.setCreateAndUpdateInfo(dto);
                            insertList.add(dto);
                        }
                    }
                }

                if (insertList.size() > 0) {
                    int start = 0;
                    int totalSize = insertList.size();
                    while (true) {
                        // 以1000条记录为单位分批存储
                        int end = Math.min(start + 1000, totalSize);
                        stateService.insertListByBatch(insertList.subList(start, end));
                        if (end >= totalSize) {
                            break;
                        }
                        start = end;
                    }
                }
                if (updateList.size() > 0) {
                    int start = 0;
                    int totalSize = updateList.size();
                    while (true) {
                        // 以1000条记录为单位分批存储
                        int end = Math.min(start + 1000, totalSize);
                        stateService.updateListByBatch(updateList.subList(start, end));
                        if (end >= totalSize) {
                            break;
                        }
                        start = end;
                    }
                }

                logger.info("开始统计历史平均运行情况");
                //重新查询昨天记录
                statList = stateService.getDataByProjectId(yesterday, null);
                statMap = new HashMap<>(16);
                for (DataStat stat : statList) {
                    statMap.put(stat.getProjectId() + stat.getStatDate(), stat);
                }

                updateList = new ArrayList<>();
                //历史平均
                List<Map<String, Object>> historySuccessDataList = stateService.historySuccessDataList();
                Map<String, Object> historySuccessMap = Maps.newHashMap();
                if (historySuccessDataList != null && historySuccessDataList.size() > 0) {
                    for (Map<String, Object> stringObjectMap : historySuccessDataList) {
                        historySuccessMap.put((String) stringObjectMap.get("projectId") + stringObjectMap.get("statHour"),
                                stringObjectMap.get("avgCount"));
                    }
                }
                List<Map<String, Object>> historyFailDataList = stateService.historyFailDataList();
                Map<String, Object> historyFailMap = Maps.newHashMap();
                if (historyFailDataList != null && historyFailDataList.size() > 0) {
                    for (Map<String, Object> stringObjectMap : historyFailDataList) {
                        historyFailMap.put((String) stringObjectMap.get("projectId") + stringObjectMap.get("statHour"),
                                stringObjectMap.get("avgCount"));
                    }
                }

                for (Project project : projectList) {
                    for (int i = 0; i < HOURS; i++) {
                        String hour = i + "";
                        if (hour.length() == 1) {
                            hour = "0" + i;
                        }
                        String statDate = yesterday + hour;
                        Integer successHistoryCount = MapUtils.getInteger(historySuccessMap, project.getId() + hour, 0);
                        Integer failHistoryCount = MapUtils.getInteger(historyFailMap, project.getId() + hour, 0);
                        String key = project.getId() + statDate;
                        DataStat dto = statMap.get(key);
                        if (dto != null) {
                            dto.setSuccessHistoryCount(successHistoryCount);
                            dto.setFailHistoryCount(failHistoryCount);
                            updateList.add(dto);
                        }
                    }
                }
                if (updateList.size() > 0) {
                    int start = 0;
                    int totalSize = updateList.size();
                    while (true) {
                        // 以1000条记录为单位分批存储
                        int end = Math.min(start + 1000, totalSize);
                        stateService.updateListByBatch(updateList.subList(start, end));
                        if (end >= totalSize) {
                            break;
                        }
                        start = end;
                    }
                }

                long total = System.currentTimeMillis() - startTime;
                logger.info("结束统计工作台运行情况: 共用时：{}", DateUtils.formatTime(total / 1000));
            } catch (Exception e) {
                logger.info("工作台统计任务执行错误.", e);
            } finally {
                lockUtils.delete(LOCK_KEY);
            }
        } else {
            logger.info("工作台统计任务已经被其他系统锁定执行。");
        }
    }

}
